﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Security.Principal;
using System.Web;
using ElectronicCommerce.Framework.Utility;

namespace ElectronicCommerce.Framework.Web
{
    /// <summary>
    /// Electronic Commerce Context
    /// </summary>
    public class ECContext
    {
        // Fields
        private readonly HttpContext _httpContext;
        //private bool _isEmpty = false;
        private DateTime _requestStartTime = DateTime.Now;

        private NameValueCollection _queryString = null;
        private NameValueCollection _form = null;

        // Methods
        #region Contructors / Create

        /// <summary>
        /// called when HttpContext is availble
        /// </summary>
        /// <param name="httpContext"></param>
        public ECContext(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
            _httpContext = httpContext;
            Initialize(httpContext.Request.QueryString, httpContext.Request.Form);
        }

        public ECContext()
        {
            Initialize(new NameValueCollection(), new NameValueCollection());
        }

        /// <summary>
        /// Create/Instatiate items that will vary based on where this object 
        /// is first created
        /// 
        /// We could wire up Path, encoding, etc as necessary
        /// </summary>
        private void Initialize(NameValueCollection queryString, NameValueCollection form)
        {
            _queryString = queryString;
            _form = form;
        }

        public static ECContext CreateEmptyContext()
        {
            ECContext context = new ECContext();
            //context._isEmpty = true;
            SaveContextToStore(context);
            return context;
        }

        public ECContext Create(HttpContext httpContext)
        {
            ECContext context = new ECContext(httpContext);
            SaveContextToStore(context);
            return context;
        }

        public static ECContext CreateFromSiteSettings()
        {
            // 还没有实现从陪置文件读取对站点的配置(比如在测试的时候构造上下文)
            // 如果出错则返加 null
            return CreateEmptyContext();
        }

        #endregion

        #region Helpers

        public string GetFromQueryString(string key)
        {
            return GetFromQueryString<string>(key, "");
        }

        public T GetFromQueryString<T>(string key)
        {
            return this.GetFromForm<T>(key, default(T));
        }

        public T GetFromQueryString<T>(string key, T defaultValue)
        {
            return this.QueryString.GetValue<T>(key, defaultValue);
        }

        public string GetFromForm(string key)
        {
            return this.Form.GetValue<string>(key, "");
        }

        public T GetFromForm<T>(string key)
        {
            return GetFromForm<T>(key, default(T));
        }

        public T GetFromForm<T>(string key, T defaultValue)
        {
            return this.Form.GetValue<T>(key, defaultValue);
        }

        public string GetFromRequest(string key)
        {
            return GetFromRequest<string>(key, "");
        }

        public T GetFromRequest<T>(string key)
        {
            return GetFromRequest<T>(key, default(T));
        }

        public T GetFromRequest<T>(string key, T defaultValue)
        {
            T result = defaultValue;

            if (this.Form.TryGetValue<T>(key, out result))
            {
                return result;
            }

            if (this.QueryString.TryGetValue<T>(key, out result))
            {
                return result;
            }

            return result;
        }

        public string MapPath(string virtualPath)
        {
            if (_httpContext != null)
                return _httpContext.Server.MapPath(virtualPath);
            else
                // Returns System\WOW for non web // return Directory.GetCurrentDirectory() + path.Replace("/", @"\").Replace("~", "");
                return PhysicalPath(virtualPath.Replace("/", Path.DirectorySeparatorChar.ToString()).TrimStart('~'));
        }

        public string PhysicalPath(string path)
        {
            return string.Concat(RootPath().TrimEnd(Path.DirectorySeparatorChar), Path.DirectorySeparatorChar.ToString(), path.TrimStart(Path.DirectorySeparatorChar));
        }

        private string _rootPath = null;
        private string RootPath()
        {
            if (_rootPath == null)
            {
                _rootPath = AppDomain.CurrentDomain.BaseDirectory;
                string dirSep = Path.DirectorySeparatorChar.ToString();

                _rootPath = _rootPath.Replace("/", dirSep);

                string filePath = "/"; // may config from config file

                if (filePath != null)
                {
                    filePath = filePath.Replace("/", dirSep);

                    if (filePath.Length > 0 && filePath.StartsWith(dirSep) && _rootPath.EndsWith(dirSep))
                    {
                        _rootPath = _rootPath + filePath.Substring(1);
                    }
                    else
                    {
                        _rootPath = _rootPath + filePath;
                    }
                }
            }
            return _rootPath;
        }

        #endregion

        // Properties
        #region Properties

        /// <summary>
        /// 请求开始时间
        /// </summary>
        public DateTime RequestStartTime
        {
            get { return _requestStartTime; }
        }

        /// <summary>
        /// 
        /// </summary>
        public IPrincipal User { get; set; }

        /// <summary>
        /// 
        /// </summary>
        private string _theme = "Default";
        public string Theme
        {
            get { return _theme; }
            set { _theme = value; }
        }

        /// <summary>
        /// Quick check to see if we have a valid web reqeust. Returns false if HttpContext == null
        /// </summary>
        public bool IsWebRequest
        {
            get { return this.Context != null; }
        }

        public bool IsHttpPost
        {
            get
            {
                return Context.Request.HttpMethod.ToUpper() == "POST";
            }
        }

        /// <summary>
        /// from https
        /// </summary>
        public static bool IsSecureConnection
        {
            get
            {
                if (HttpContext.Current == null)
                    return false;
                else
                    return HttpContext.Current.Request.IsSecureConnection;
            }
        }

        /// <summary>
        /// 判断当前登录用户是否已经认证过
        /// </summary>
        public bool IsAuthenticated
        {
            get { return User != null && User.Identity.IsAuthenticated; }
        }

        public HttpContext Context
        {
            get { return _httpContext; }
        }

        public NameValueCollection QueryString
        {
            get { return _queryString; }
        }

        public NameValueCollection Form
        {
            get { return _form; }
        }

        #endregion

        #region State

        private static readonly string dataKey = "ECContextStore";

        [ThreadStatic]
        private static ECContext _currentContext = null;

        /// <summary>
        /// Returns the current instance of the CSContext from the ThreadData Slot. If one is not found and a valid HttpContext can be found,
        /// it will be used. Otherwise, an exception will be thrown. 
        /// </summary>
        public static ECContext Current
        {
            get
            {
                HttpContext httpContext = HttpContext.Current;

                if (httpContext != null)
                {
                    if (httpContext.Items.Contains(dataKey))
                        return httpContext.Items[dataKey] as ECContext;
                    else
                    {
                        ECContext context = new ECContext(httpContext);
                        SaveContextToStore(context);
                        return context;
                    }
                }
                else if (_currentContext == null)
                {
                    ECContext context = CreateFromSiteSettings();
                    if (context != null)
                        SaveContextToStore(context);
                }

                if (_currentContext == null)
                    throw new Exception("No ECContext exists in the Current Application. AutoCreate fails since HttpContext.Current is not accessible.");

                return _currentContext;
            }
        }

        private static void SaveContextToStore(ECContext context)
        {
            if (context.IsWebRequest)
            {
                context.Context.Items[dataKey] = context;
            }
            else
            {
                _currentContext = context;
            }
        }

        public static void Unload()
        {
            _currentContext = null;
        }

        #endregion
    }
}
